package com.rr.sc.bo.impl;

import java.util.Arrays;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.rr.sc.bo.UserBo;
import com.rr.sc.dao.AccountDao;
import com.rr.sc.dao.CategoryDao;
import com.rr.sc.dao.TransactionDao;
import com.rr.sc.dao.UserDao;
import com.rr.sc.model.Account;
import com.rr.sc.model.Category;
import com.rr.sc.model.Transaction;
import com.rr.sc.model.User;
import com.rr.sc.security.SecurityUtils;

@Service
public class UserBoImpl implements UserBo {
    private UserDao userDao;
    private CategoryDao categoryDao;
    private AccountDao accountDao;
    private TransactionDao transactionDao;

    @Autowired
    private UserBoImpl(UserDao userDao, CategoryDao categoryDao, AccountDao accountDao, TransactionDao transactionDao) {
	super();
	this.userDao = userDao;
	this.categoryDao = categoryDao;
	this.accountDao = accountDao;
	this.transactionDao = transactionDao;
    }

    public void saveOrUpdate(User user) throws Exception {

	if (user.getId() == null) {

	    user.setPassword(SecurityUtils.getMD5(user.getPassword()));
	    userDao.saveOrUpdate(user);

	    List<Category> baseCategories = categoryDao.getByUserId(null, false);
	    for (Category category : baseCategories) {
		copyCategory(category, user);
	    }
	} else {
	    userDao.saveOrUpdate(user);
	}
    }

    private Category copyCategory(Category category, User user) throws Exception {
	List<Category> testExistingCategory = categoryDao.getByUserIdAndName(Arrays.asList(user.getId()), category.getName());
	if (testExistingCategory != null) {
	    if (testExistingCategory.size() == 1) {
		return testExistingCategory.get(0);
	    } else if (testExistingCategory.size() > 1) {
		throw new Exception("Many identical categories found for user.");
	    }
	}
	Category newCategory = new Category();
	newCategory.setDescription(category.getDescription());
	newCategory.setName(category.getName());
	newCategory.setUser(user);

	if (category.getParentCategory() != null) {
	    List<Category> posibleParent = categoryDao.getByUserIdAndName(Arrays.asList(user.getId()), category.getParentCategory()
		    .getName());
	    if (posibleParent == null || posibleParent.size() == 0) {
		// create parent
		newCategory.setParentCategory(copyCategory(category.getParentCategory(), user));
	    } else if (posibleParent.size() > 1) {
		throw new Exception("Many parent categories found: this is imposible !");
	    } else {
		newCategory.setParentCategory(posibleParent.get(0));
	    }
	}
	categoryDao.saveOrUpdate(newCategory);

	return newCategory;
    }

    public User get(Long id) {
	return userDao.get(id);
    }

    public void delete(User user) {
	List<Transaction> userTransactions = transactionDao.getFiltered(Arrays.asList(user.getId()), 0, 0, null, null, null, null);
	for (Transaction transaction : userTransactions) {
	    transactionDao.delete(transaction);
	}
	List<Category> userCategories = categoryDao.getByUserId(Arrays.asList(user.getId()), false);
	for (Category category : userCategories) {
	    categoryDao.delete(category);
	}
	List<Account> userAccounts = accountDao.getByUserIds(Arrays.asList(user.getId()));
	for (Account account : userAccounts) {
	    accountDao.delete(account);
	}

	userDao.delete(user);
    }

    public List<User> getAll() {
	return userDao.getAll();
    }

    public User get(String username) {
	return userDao.get(username);
    }
}
